using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace _2DGame
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class GameObject : CollisionObject
    {
        protected bool canBeCollidedWith = false;

        protected Vector2 position = new Vector2(0,0);
        protected Vector2 velocity = new Vector2(0,0);

        protected float rotation = 0.0f;
        protected float angularVelocity = 0.0f;

        public bool CanBeCollidedWith
        {
            get { return canBeCollidedWith; }
        }

        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }

        public Vector2 Velocity
        {
            get { return velocity; }
            set { velocity = value; }
        }

        public float Rotation
        {
            get { return rotation; }
            set { rotation = value; }
        }

        public GameObject(String fromFilename, SpriteBlendMode fromBlendMode) :
            base(fromFilename, fromBlendMode)
        {
        }


        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            position += velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
            rotation += angularVelocity * (float)gameTime.ElapsedGameTime.TotalSeconds;

            // Wrap the rotation so it stays between between 0 and 2PI, 
            if (rotation < 0)
                rotation += (float)Math.PI * 2.0f;
            if (rotation >= (float)Math.PI * 2.0f)
                rotation -= (float)Math.PI * 2.0f;

            Resources.World.ObjectMoved(this);
        }

        public override void Draw()
        {
            Point screenPosition = Resources.World.GetScreenPosition(position);

            Rectangle screenRect = new Rectangle();

            screenRect.X = screenPosition.X;
            screenRect.Y = screenPosition.Y;
            screenRect.Width = (int)(Texture.Width * Resources.World.DrawScale);
            screenRect.Height = (int)(Texture.Height * Resources.World.DrawScale);

            Resources.SpriteBatch.Draw(
                Texture,
                screenRect,
                null,
                Color.White,
                rotation,
                // set the origin as the middle of the sprite so it rotates around there
                new Vector2((int)(Texture.Width / 2.0f), (int)(Texture.Height / 2.0f)),
                SpriteEffects.None,
                0.0f);
        }

        public virtual void Teleport(Vector2 newPosition)
        {
            position = newPosition;
        }

        public bool IsColliding(GameObject otherObject)
        {
            Rectangle textureRectangle = GetVisibleTextureRectangle();
            Rectangle otherTextureRectangle = otherObject.GetVisibleTextureRectangle();

            Matrix myTransform =
                Matrix.CreateTranslation(new Vector3(-textureRectangle.Width / 2, -textureRectangle.Height / 2, 0.0f)) *
                Matrix.CreateRotationZ(rotation) *
                Matrix.CreateTranslation(new Vector3(position, 0.0f));

            Matrix otherTransform =
                Matrix.CreateTranslation(new Vector3(-otherTextureRectangle.Width / 2, -otherTextureRectangle.Height / 2, 0.0f)) *
                Matrix.CreateRotationZ(otherObject.rotation) *
                Matrix.CreateTranslation(new Vector3(otherObject.position, 0.0f));

            return CollisionObject.IsColliding(myTransform, this, otherTransform, otherObject);
        }

        public virtual void TouchMap(List<Map.CollisionInfo> collisions)
        {
            Resources.World.RemoveObject(this);
        }

        public virtual bool Touch(GameObject otherObject)
        {
            return false;
        }
    }
}